﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Text;

namespace LX.Core.Aop
{
    public abstract class Aspect : RealProxy
    {
        public abstract void PreProcess();
        public abstract void PostProcess();
        public abstract ReturnMessage ProcessError(Exception error, IMethodCallMessage msg);

        MarshalByRefObject _target = null;

        protected Aspect(Type serverType, MarshalByRefObject target)
            : base(serverType)
        {
            _target = target;
        }

        public override IMessage Invoke(IMessage msg)
        {
            IMessage result = msg;
            if (msg is IConstructionCallMessage)
            {
                IConstructionCallMessage constructCallMsg = msg as IConstructionCallMessage;

                RealProxy defaultProxy = RemotingServices.GetRealProxy(_target);

                PreProcess();

                //如果不做下面这一步，_target还是一个没有直正实例化被代理对象的透明代理，
                //这样的话，会导致没有直正构建对象。
                IConstructionReturnMessage contmsg = defaultProxy.InitializeServerObject(constructCallMsg);
                if (contmsg.Exception != null)
                {
                    result = ProcessError(contmsg.Exception, constructCallMsg);
                }
                else
                {

                    ////本类是一个RealProxy，它可通过GetTransparentProxy函数得到透明代理
                    result =
                        System.Runtime.Remoting.Services.EnterpriseServicesHelper.CreateConstructionReturnMessage(
                            constructCallMsg, (MarshalByRefObject) GetTransparentProxy());

                }

                PostProcess();

            }
            else if (msg is IMethodCallMessage)
            {
                var callMsg = msg as IMethodCallMessage;
                var copiedArgs = new object[callMsg.Args.Length];
                callMsg.Args.CopyTo(copiedArgs, 0);
                try
                {
                    PreProcess();
                    object returnValue = callMsg.MethodBase.Invoke(this._target, copiedArgs);
                    result = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, callMsg.LogicalCallContext, callMsg);
                    PostProcess();
                }
                catch (Exception ex)
                {
                    result = ProcessError(ex, callMsg);
                }
               
            }
            return result;
        }
    }
}
